package org.bartcr.tools.io.scanner;

import org.apache.commons.io.filefilter.AndFileFilter;
import org.apache.commons.io.filefilter.DelegateFileFilter;
import org.apache.commons.io.filefilter.FileFilterUtils;

import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.util.Set;

/**
 * A directory scanner to list or process files and directories under a specific basedir.
 * <p/>
 * The basic scanner will list all files in the directory:
 *
 * <pre>{@code
 * new DirectoryScanner(baseDir).list(); // Get all files under basedir
 * }</pre>
 *
 * The scanner can be set up with processor's to perform some tasks on these files.
 * <p/>
 * Filters can be added to the scanner to get a more fine-grained selection of files.
 */
public final class DirectoryScanner {

    private final File baseDir;
    private final AndFileFilter fileFilter;

    public DirectoryScanner(File baseDir) {
        if (baseDir == null) {
            throw new NullPointerException("'baseDir' should not be null");
        }
        this.baseDir = baseDir;
        this.fileFilter = new AndFileFilter();
        this.fileFilter.addFileFilter(FileFilterUtils.trueFileFilter());
    }

    /**
     * Add a {@link FileFilter} to the <tt>DirectoryScanner</tt>.
     *
     * @param filter the filter to add
     * @return the <tt>DirectoryScanner</tt> instance
     */
    public DirectoryScanner fileFilter(FileFilter filter) {
        fileFilter.addFileFilter(new DelegateFileFilter(filter));
        return this;
    }

    public DirectoryScanner filenameFilter(FilenameFilter filter) {
        fileFilter.addFileFilter(new DelegateFileFilter(filter));
        return this;
    }

    /**
     * @return the set of files compiled by this DirectoryScanner
     */
    public Set<File> list() {
        return getFilesWithWalker(baseDir);
    }

    private Set<File> getFilesWithWalker(File dir) {
        ScannerDirectoryWalker walker = new ScannerDirectoryWalker(FileFilterUtils.trueFileFilter(), fileFilter);
        return walker.list(dir);
    }
}
